//
//  OGLApp.cpp
//  GSP420_Week3_iLab
//
//  Created by Scott Nelson on 5/18/11.
//  Copyright 2011 NA. All rights reserved.
//

#include "OGLApp.h"

//Constructor
OGLApp* OGLApp::Instance()
{
    static OGLApp instance;
    return &instance;
}

//Destructor
OGLApp::~OGLApp(){};

//Initialization functions
bool OGLApp::onInit() 
{
    /*
     This section will include the code to initialize all OpenGL subsystems
     as well as initialize all of the other cores.
     */

    //Set display properties
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); //Set up a display buffer, enable double buffering, blending and depth testing
    glutInitWindowSize(1000, 1000); //Set the width and height of the window
    glutInitWindowPosition(100, 100); //Set window position
    glutCreateWindow("GSP 420"); //Set window caption
    glEnable(GL_CULL_FACE); //Enable backface culling
    
    return true;
}

//Checks for events and sends messages to the update function
void OGLApp::onEvent()
{
    /*
     This section will listen for events and dispatch the appropriate
     message for the events that occur.
     */
    
    //======================================================
    //                      TESTING
    //======================================================
    
    //This is simply a test, events will not look like this when they 
    //are finished
    Message newMessage;
    
    newMessage.ID = 2;
    newMessage.position.x_Pos = -2;
    newMessage.position.y_Pos = 2;
    newMessage.position.z_Pos = 0;
    newMessage.rotation.x_Rot = 1;
    newMessage.rotation.y_Rot = 0;
    newMessage.rotation.z_Rot = 0;
    newMessage.scale.x_Scl = 1;
    newMessage.scale.y_Scl = 1;
    newMessage.scale.z_Scl = 1;
    newMessage.objectType = PYRAMID;
    
    mMessageList.push_back(newMessage);
    printf("\nonEvent");
}

//Receives events from the onEvent function and updates game objects
void OGLApp::onUpdate()
{
    //======================================================
    //                      TESTING
    //======================================================
    //This is a test of the update function and is subject to change
    //The message changes the orignial object based on its settings
    
    //Iterator to cycle through the mObjectList
    vector<GraphicsObject>::iterator iter;
    
    for(int i = 0; i < mMessageList.size(); ++i)
    {
        
        for(iter = mObjectList.begin(); iter != mObjectList.end(); ++iter)
        {
            if(iter->ID() == mMessageList[i].ID)
            {
                iter->ID();
                iter->setObjectPosition(mMessageList[i].position);
                iter->setObjectRotation(mMessageList[i].rotation);
                iter->setObjectScale(mMessageList[i].scale);
                iter->setObjectType(mMessageList[i].objectType);
            }
        }
    }
    
    printf("\nonUpdate");
}

//Renders objects to the screen
void OGLApp::onRender()
{
    
    //Handle drawing
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //Clear background of window
    glClear(GL_COLOR_BUFFER_BIT); //Clear the color buffer
    glLoadIdentity(); //Load identity matrix to reset drawing locations
    
    //Translate scene back
    glTranslatef(0.0f, 0.0f, -6.0f);
    
    //Loop through the mObjectList vector and draw the objects
    for(int i = 0; i < mObjectList.size(); ++i)
    {
        drawGraphics(i);
    }
    
    //Temporary
	rotationAngle++; //Rotation angle for object
    
    glutSwapBuffers();
}

//Exits program and destroys objects
void OGLApp::onExit()
{
    /*
     This section will call the proper functions to
     destroy objects, free allocated memory, and destroy
     the singleton
     */
    
    printf("\nonExit");
    OGLApp::~OGLApp(); 
    printf("\nDestructor Called");
}

//Add an element to the mObjectList vector
void OGLApp::addElement(GraphicsObject &object)
{
    mObjectList.push_back(object);
}

//Remove an element from the mObjectList vector regardless of position
void OGLApp::removeElement(GraphicsObject &object)
{
    
    //Iterator to cycle through the mObjectList
    vector<GraphicsObject>::iterator iter;
    
    //Loop through the list and delete the correct object
    for(iter = mObjectList.begin(); iter != mObjectList.end(); ++iter)
    {
        //Compare the ID of the passted object with that of the iterator
        if(iter->ID() == object.ID())
        {
            //Remove the object
            iter = mObjectList.erase(iter);
            iter --; //Skip back a space as to not to leave holes
        }
    }
}

//Draws the objects in the mObjectList vector to the screen 
void OGLApp::drawGraphics(int num)
{
    glPushMatrix();
    glTranslatef(mObjectList[num].getObjectPositionX(), mObjectList[num].getObjectPositionY(), mObjectList[num].getObjectPositionZ());
    
    //If the object has 0 for rotation parameteres, the object will not rotate. This HAS to be here or else the objects will rotate along the z axis even
    //though the parameter says zero.
    if(mObjectList[num].getObjectRotationX() == 0.0 && mObjectList[num].getObjectRotationY() == 0.0 && mObjectList[num].getObjectRotationZ() == 0.0)
    {
        glRotatef(0.0, mObjectList[num].getObjectRotationX(), mObjectList[num].getObjectRotationY(), mObjectList[num].getObjectRotationZ());
    }
    else
    {
        //Format for rotations: glRotatef(rotationAngle, 0.0, 0.0, 0.0)
        glRotatef(rotationAngle, mObjectList[num].getObjectRotationX(), mObjectList[num].getObjectRotationY(), mObjectList[num].getObjectRotationZ());
    }
    
    glScalef(mObjectList[num].getObjectScaleX(), mObjectList[num].getObjectScaleY(), mObjectList[num].getObjectScaleZ());
    
    //Draw object
    GraphicsObject::drawObject(mObjectList[num].getObjectType());
    glPopMatrix();
}
